<?php
/**
 * @author spenceryg
 * @date 2022/12/5
 * @time 5:51 下午
 * @focus love & life
 */


namespace app\auto\controller;

use app\auto\business\TableBusiness;
use app\common\lib\word\Word;
use hg\apidoc\annotation as Apidoc;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
use think\facade\View;
use think\response\Json;

/**
 * 数据模拟
 * Class Faker
 * @package app\auto\controller
 * @Apidoc\Title 数据模拟
 * @Apidoc\Desc 对auto的表进行模拟注入数据
 */
class Faker extends \app\BaseController
{
    public $faker = null;
    public $faker_type = [
        'varchar' => [
            'word' => [
                'cname' => 'n个字',
                'param' => '',
                'full' => '{$rule}'
            ],
            'name' => [
                'cname' => '姓名',
                'param' => '',
                'full' => '{$rule}'
            ],
            'title' => [
                'cname' => '职业',
                'param' => '',
                'full' => '{$rule}'
            ],


        ],
        'text' => [
            'text' => [
                'cname' => 'n个字的文章',
                'param' => '',
                'full' => '{$rule}'
            ],
            'sentence' => [
                'cname' => 'n个词的句子',
                'param' => '',
                'full' => '{$rule}'
            ],
        ],
        'longtext' => [
            'text' => [
                'cname' => 'n个字的文章',
                'param' => '',
                'full' => '{$rule}'
            ],
            'paragraph' => [
                'cname' => 'n句话的段落',
                'param' => '',
                'full' => '{$rule}'
            ],

        ],
        'int' => [
            'randomNumber' => [
                'cname' => 'n位数',
                'param' => '',
                'full' => '{$rule}'
            ]
        ],
        'tinyint' => [
            'set' => [
                'cname' => '数据集',
                'param' => '',
                'full' => '0,1'
            ]
        ]
    ];

    /**
     * Faker constructor.
     * @param App $app
     */
    public function __construct(App $app)
    {
        $faker = \Faker\Factory::create('zh_CN');
        $faker->addProvider(new \SupGeekRod\FakerZh\ZhCnDataProvider($faker));
        $this->faker = $faker;
    }

    /**
     * getTypeOptionHtml
     * @param $type
     * @return string
     */
    private function getTypeOptionHtml($type): string
    {
        $arr = $this->faker_type[$type] ?: [];
        $html = <<<EOF
<select name="type[]"  class="select3" lay-ignore style="width: 100%">
EOF;
        foreach ($arr as $key => $item) {
            $html .= <<<EOF
<option value="{$key}">{$item['cname']}</option>
EOF;

        }
        return $html;
    }


    /**
     * getFullHtml
     * @param $type
     * @return string
     */
    private function getFullHtml($type): string
    {
        $html = <<<EOF
<input type="text" class="layui-input" value="{rule}" name="full[]">
EOF;

        if ($type == 'tinyint') {
            $html = <<<EOF
<input type="text" class="layui-input" value="0,1" name="full[]">
EOF;

        }
        return $html;
    }


    /**
     * index
     * @return string|Json
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function index()
    {
        if (request()->isPost()) {
            $data = input();
            $count = $data['count'] ?: 10;
            $table_id = $data['table_id'];
            if (!$table_id) {
                return error('表名不能为空！');
            }
            $table = \app\auto\model\Table::find($table_id);
            $class = "app\\common\\model\\" . TableBusiness::tableToClass($table['name']);
            $relation_id = input('relation_id');

            if ($relation_id) {
                $relation_type = input('relation');
                if ($relation_type == 'hasMany') {
                    $relation = \app\auto\model\Relation::find($relation_id);
                    $table_master = \app\auto\model\Table::find($relation['table_id_master']);
                    $master_class = "app\\common\\model\\" . TableBusiness::tableToClass($table_master['name']);
                    $masters = $master_class::select();
                    $real_rules = [];
                    foreach ($data['field'] as $key => $val) {
                        $field = \app\auto\model\Field::find($val);
                        if (in_array($data['field'][$key], $data['is_faker']) && $field['name']!= $relation['sliver_field']) {
                            $this_rule = [];
                            $this_rule['field_name'] = $field['name'];
                            $this_rule['faker_func'] = $data['type'][$key];
                            $this_rule['faker_param'] = $data['param'][$key] ? explode(',', $data['param'][$key]) : [];
                            $this_rule['full'] = $data['full'][$key];
                            $this_rule['is_relation'] = $field['is_relation'];
                            $real_rules[] = $this_rule;
                        }
                    }
                    foreach ($masters as $master) {
                        for ($i = 0; $i < $count; $i++) {
                            $this_data = [];
                            $this_data[$relation['sliver_field']] = $master['id'];
                            foreach ($real_rules as $rule) {
                                if (strpos($rule['full'], '{rule}') === false) {
                                    $fulls = explode(',', $rule['full']);
                                    $this_data[$rule['field_name']] = $fulls[array_rand($fulls)];
                                } else {
                                    if ($rule['is_relation']) {
                                        $random_str = self::getRandomIdByField($rule['field_name']);
                                    } else {
                                        if (is_numeric($rule['faker_func'])) {
                                            $random_str = Word::getRandomWordByCatId($rule['faker_func']);
                                        } else {
                                            $function = $rule['faker_func'];
                                            if (!$rule['faker_param']) {
                                                $random_str = $this->faker->$function();
                                            } else {

                                                $random_str = call_user_func_array([$this->faker, $function], $rule['faker_param']);
                                            }
                                        }
                                    }
                                    $this_data[$rule['field_name']] = str_replace('{rule}', $random_str, $rule['full']);
                                }
                            }
                            $class::create($this_data);
                        }
                    }
                }
                if ($relation_type == 'belongsToMany') {
                    $max_count = $class::count();
                    // 不希望过多的浪费时间空间 所以去最小值
                    $count = min($max_count, $count);
                    $relation = \app\auto\model\Relation::find($relation_id);
                    if($table_id == $relation['table_id_master']) {
                        $table_other  = \app\auto\model\Table::find($relation['table_id_sliver']);
                        $class = "app\\common\\model\\" . TableBusiness::tableToClass($table_other['name']);
                        $class_arr = $class::select();
                        $table_field = str_replace(env('DATABASE.PREFIX'), '', $table['name']) . '_id';
                        $table_field_other = str_replace(env('DATABASE.PREFIX'), '', $table_other['name']) . '_id';
                        $relation_table_name = $table['name'] . '_' . str_replace(env('DATABASE.PREFIX'), '', $table_other['name']);
                        foreach ($class_arr as $item) {
                            for ($i = 0; $i < $count; $i++) {
                                $random_id = self::getRandomIdByField($table_field);
                                $find = Db::table($relation_table_name)->where($table_field, $random_id)
                                    ->where($table_field_other,  $item['id'])->find();
                                if($find){
                                    continue;
                                }else{
                                    Db::table($relation_table_name)->insert([
                                        $table_field => $random_id,
                                        $table_field_other => $item['id']
                                    ]);
                                }
                            }
                        }
                    } else {
                        $table_other  = \app\auto\model\Table::find($relation['table_id_master']);
                        $class = "app\\common\\model\\" . TableBusiness::tableToClass($table_other['name']);
                        $class_arr = $class::select();
                        $table_field = str_replace(env('DATABASE.PREFIX'), '', $table['name']) . '_id';
                        $table_field_other = str_replace(env('DATABASE.PREFIX'), '', $table_other['name']) . '_id';
                        $relation_table_name = $table_other['name'] . '_' . str_replace(env('DATABASE.PREFIX'), '', $table['name']);
                        foreach ($class_arr as $item) {
                            for ($i = 0; $i < $count; $i++) {
                                $random_id = self::getRandomIdByField($table_field);
                                $find = Db::table($relation_table_name)->where($table_field, $random_id)
                                    ->where($table_field_other,  $item['id'])->find();
                                if($find){
                                    continue;
                                }else{
                                    Db::table($relation_table_name)->insert([
                                        $table_field => $random_id,
                                        $table_field_other => $item['id']
                                    ]);
                                }
                            }
                        }
                    }
                }
            } else {
                $real_rules = [];
                foreach ($data['field'] as $key => $val) {
                    $field = \app\auto\model\Field::find($val);
                    if (in_array($data['field'][$key], $data['is_faker'])) {
                        $this_rule = [];
                        $this_rule['field_name'] = $field['name'];
                        $this_rule['faker_func'] = $data['type'][$key];
                        $this_rule['faker_param'] = $data['param'][$key] ? explode(',', $data['param'][$key]) : [];
                        $this_rule['full'] = $data['full'][$key];
                        $this_rule['is_relation'] = $field['is_relation'];
                        $real_rules[] = $this_rule;
                    }
                }

                for ($i = 0; $i < $count; $i++) {
                    $this_data = [];
                    foreach ($real_rules as $rule) {
                        if (strpos($rule['full'], '{rule}') === false) {
                            $fulls = explode(',', $rule['full']);
                            $this_data[$rule['field_name']] = $fulls[array_rand($fulls)];
                        } else {
                            if ($rule['is_relation']) {
                                $random_str = self::getRandomIdByField($rule['field_name']);
                            } else {
                                if (is_numeric($rule['faker_func'])) {
                                    $random_str = Word::getRandomWordByCatId($rule['faker_func']);
                                } else {
                                    $function = $rule['faker_func'];
                                    if (!$rule['faker_param']) {
                                        $random_str = $this->faker->$function();
                                    } else {

                                        $random_str = call_user_func_array([$this->faker, $function], $rule['faker_param']);
                                    }
                                }
                            }
                            $this_data[$rule['field_name']] = str_replace('{rule}', $random_str, $rule['full']);
                        }
                    }
                    $class::create($this_data);
                }
            }

            return success();
        } else {
            $tables = \app\auto\model\Table::select();
            View::assign('tables', $tables);
            return View::fetch();
        }

    }


    /**
     * 获取随机 存在的id
     * getRandomIdByField
     * @param $field
     * @return int|mixed
     */
    public static function getRandomIdByField($field)
    {
        $table_name = env('DATABASE.PREFIX') . '_' . str_replace('_id', '', $field);
        $class = "app\\common\\model\\" . TableBusiness::tableToClass($table_name);
        $ids = $class::column('id');
        return $ids ? $ids[array_rand($ids)] : 0;
    }


    /**
     * add
     */
    public function add()
    {
        $data = input();

    }

    /**
     * getFields
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getFields()
    {
        $table_id = input('table_id');
        $fields = \app\auto\model\Field::where('table_id', $table_id)->select();
        $html = <<<EOF
<tr>
<th style="width: 140px">
    字段中文名
</th>
<th style="width: 120px">
    类型
</th>
<th style="width: 160px">
    规则类型
</th>
<th style="width: 200px">
    规则参数
</th>
<th>
    自定义
</th>
</tr>
EOF;
        $expect_fields = [
            'id',
            'create_time',
            'update_time',
            'delete_time'
        ];
        foreach ($fields as $field) {
            if (!in_array($field['name'], $expect_fields)) {
                $type_html = $this->getTypeOptionHtml($field['type']);
                $full_html = $this->getFullHtml($field['type']);
                $html .= <<<EOF
<tr>
<td>
<input type="hidden" name="field[]" value="{$field['id']}">
<input type="checkbox"  name="is_faker[]" value="{$field['id']}" title="{$field['comment']}" checked>
</td>
<td>
{$field['type']}({$field['length']})
</td>
<td>
{$type_html}
</select>
</td>
<td>
<input type="text" class="layui-input" value="" name="param[]">
</td>
<td>
{$full_html}
</td>
</tr>
EOF;
            }
        }
        return success('', $html);

    }




    /**
     * getCatByWord
     * @return Json
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getCatByWord(): Json
    {
        $word = input('word');
        if (!$word) {
            return success('', '<option value="">请选择</option>>');
        }
        $arr = Word::getCat($word);
        $html = '<option value="">请选择</option>>';
        foreach ($arr as $item) {
            $html .= <<<EOF
<option value="{$item['id']}">{$item['id']}__{$item['name']}({$item['count']}个)</option>
EOF;

        }
        return success('', $html);
    }

    /**
     * getWordsById
     * @return Json
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getWordsById(): Json
    {
        $id = input('id');
        $arr = Word::getCatWordsDemo($id);
        $words_group = array_chunk(array_column($arr, 'word'), 8);
        $res = [];
        foreach ($words_group as $group) {
            $res[] = implode('  ', $group);
        }
        $html = implode("\r\n", $res);
        return success('', $html);
    }


    /**
     * 获取表的一对多，多对多关联关系
     * getRelationType
     * @return Json
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getRelationTypeByTableId(): Json
    {
        $id = input('id');
        $hasMany = \app\auto\model\Relation::where('type', 'hasMany')
            ->where('table_id_sliver', $id)->find();
        $html = '<option value="">选择关系</option>>';
        if ($hasMany) {
            $html .= '<option value="hasMany">一对多</option>';
        }
        $belongsToMany = \app\auto\model\Relation::where('type', 'belongsToMany')
            ->where('table_id_sliver', $id)->find();
        $belongsToMany1 = \app\auto\model\Relation::where('type', 'belongsToMany')
            ->where('table_id_master', $id)->find();
        if ($belongsToMany || $belongsToMany1) {
            $html .= '<option value="belongsToMany">多对多</option>';
        }
        return success('', $html);
    }


    /**
     * 获取条件表html
     * getTable2Html
     */
    public function getTable2Html(): Json
    {
        $html = ' <option value="">请选择条件数据表</option>';
        $id = input('id');
        $type = input('type');
        if ($type == 'hasMany') {
            $relations = \app\auto\model\Relation::where('type', 'hasMany')
                ->where('table_id_sliver', $id)->column('table_id_master as table_id,id');
            foreach ($relations as $relation) {
                $table = \app\auto\model\Table::find($relation['table_id']);
                $html .= <<<EOF
<option value="{$relation['id']}">{$table['comment']}-{$table['name']}</option>
EOF;
            }
        }
        if ($type == 'belongsToMany') {
            $relations = \app\auto\model\Relation::where('type', 'belongsToMany')
                ->where('table_id_sliver', $id)->column('table_id_master as table_id,id');

            $relations1 = \app\auto\model\Relation::where('type', 'belongsToMany')
                ->where('table_id_master', $id)->column('table_id_sliver as table_id,id');

            $relations = array_merge($relations, $relations1);
            foreach ($relations as $relation) {
                $table = \app\auto\model\Table::find($relation['table_id']);
                $html .= <<<EOF
<option value="{$relation['id']}">{$table['comment']}-{$table['name']}</option>
EOF;
            }
        }

        return success('', $html);
    }
}
